from gevent import monkey

monkey.patch_all()
from gevent.pool import Pool
from queue import Queue

import schedule
import time
from IPProxyPool.core.db.mongo_pool import MongoProxiesPool
from IPProxyPool.core.proxy_validate.httpbin_validator import check_proxy
from IPProxyPool.settings import MAX_SCORE,TEST_PROXIES_ASYNC_COUNT,TEST_PROXIES_INTERVAL


# 目的: 检查代理IP可用性, 保证代理池中代理IP基本可用
# 思路
#
# 从数据库中获取所有代理IP
# 遍历代理IP列表
# 检查代理可用性
# 如果代理不可用, 让代理分数-1, 如果代理分数等于0就从数据库中删除该代理, 否则就让代理的分数-1
# 如果代理可用, 就恢复该代理的分数
# 为了提高检查的速度, 使用异步来执行检测任务

# 在proxy_test.py中, 创建ProxyTester类
# 提供一个 run 方法, 用于检查代理IP的可用性
class ProxyTester:

    def __init__(self):
        # 初始化获取数据库链接
        self.mongo_pool = MongoProxiesPool()
        #     创建队列和协程池
        self.queue = Queue()
        self.coroutine_pool = Pool()

    def __check_callback(self, temp):
        # 下面第一次完成之后执行他的callback方法，而这个callback再次执行检测任务，再次callback自己
        self.coroutine_pool.apply_async(self.__check_one_proxy, callback=self.__check_callback)

    def run(self):
        # 从数据库中获取所有的代理
        proxies = self.mongo_pool.find_all()
        # 遍历代理
        for proxy in proxies:
            # 把代理放入到队列当中
            self.queue.put(proxy)

        # 开启对个异步任务，来检测代理，通过配置文件指定开启几个线程
        for i in range(TEST_PROXIES_ASYNC_COUNT):
            # 通过一部坏掉，使用协程池，使用死循环不断执行这个方法
            self.coroutine_pool.apply_async(self.__check_one_proxy, callback=self.__check_callback)
        # 让当前线程等待队列任务完成
        self.queue.join()

    def __check_one_proxy(self):
        # 检测一个代理
        # proxy参数不再直接传入，从队列当中拿到，检测完毕之后放到task_done方法
        proxy = self.queue.get()
        # 检测代理
        proxy = check_proxy(proxy)
        # 如果不可用，分数-1
        if proxy.speed == -1:
            proxy.score -= 1
            # 如果分数减到了0 从数据库中删除
            if proxy.score == 0:
                self.mongo_pool.delete_one(proxy)
            # 如果没有那么更新数据
            else:
                self.mongo_pool.update_one(proxy)
        # 如果可用，分数恢复到初始满分
        else:
            proxy.score = MAX_SCORE
            self.mongo_pool.update_one(proxy)

        # 检测完毕后添加到task_done方法中
        self.queue.task_done()

    # 创建类方法，定时执行检测任务
    @classmethod
    def start(cls):
        # 创建本类对象
        proxy_tester = cls()
        # 调用run方法
        proxy_tester.run()

        # 按照配置文件指定的时间间隔执行一次run方法
        schedule.every(TEST_PROXIES_INTERVAL).hours.do(proxy_tester.run)
        while 1:
            time.sleep(60) # 每60秒检测一次是不是过去十二个小时了

if __name__ == '__main__':
    # pt = ProxyTester()
    # pt.run()

    ProxyTester.start()